package com.dylan.历史.util;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.tuple.Pair;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 加密/解密工具
 */
public class EncryptUtil {
    private static final String ENCRYPTION_RSA = "RSA";
    private static final int RSA_KEY_SIZE = 1024;

    /**
     * 使用AES加密，并生成16进制字符串
     * @param content 待加密的字符串
     * @param key 加密的KEY
     * @return 加密后的16进制字符串
     */
    public static String aesEncryptToHex(String content, String key) {
        byte[] originalEncrypt = aesOriginalEncrypt(content, key);
        return Hex.encodeHexString(originalEncrypt);
    }

    /**
     * 使用AES从16进制字符串解密
     * @param content 待解密的16进制字符串
     * @param key 加密时使用的KEY
     * @return 解密后的字符串
     */
    public static String aesDecryptFromHex(String content, String key) {
        try {
            byte[] originalDecrypt = Hex.decodeHex(content.toCharArray());
            return aesOriginalDecrypt(originalDecrypt, key);
        } catch (DecoderException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 使用MD5加密，并生成16进制的消息摘要
     * @param content 待加密的字符串
     * @return 加密后的16进制消息摘要
     */
    public static String md5HexDigest(String content) {
        return DigestUtils.md5Hex(content);
    }

    /**
     * 使用SHA1加密，并生成16进制的消息摘要
     * @param content 待加密的字符串
     * @return 加密后的16进制消息摘要
     */
    public static String sha1HexDigest(String content) {
        return DigestUtils.sha1Hex(content);
    }


    /**
     * 使用SHA256加密，并生成16进制的消息摘要
     * @param content 待加密的字符串
     * @return 加密后的16进制消息摘要
     */
    public static String sha256Hex(String content) {
        return DigestUtils.sha256Hex(content);
    }

    private static byte[] aesOriginalEncrypt(String content, String key) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
            sr.setSeed(key.getBytes());
            kgen.init(128, sr);
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec sk = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
            cipher.init(Cipher.ENCRYPT_MODE, sk);// 初始化
            return cipher.doFinal(byteContent);// 加密
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
    }

    private static String aesOriginalDecrypt(byte[] content, String key) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
            sr.setSeed(key.getBytes());
            kgen.init(128, sr);
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec sk = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            cipher.init(Cipher.DECRYPT_MODE, sk);// 初始化
            byte[] result = cipher.doFinal(content);
            return new String(result, StandardCharsets.UTF_8);// 加密
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
    }


    public static String rsaEncryptToHex(String content, String publicKey) {
        try {
            //base64编码的公钥
            byte[] decoded = Base64.decodeBase64(publicKey);
            RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(ENCRYPTION_RSA).generatePublic(new X509EncodedKeySpec(decoded));
            //RSA加密
            Cipher cipher = Cipher.getInstance(ENCRYPTION_RSA);
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            return Base64.encodeBase64String(cipher.doFinal(content.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String rsaDecryptFromHex(String content, String privateKey) {
        try {
            //64位解码加密后的字符串
            byte[] inputByte = Base64.decodeBase64(content.getBytes(StandardCharsets.UTF_8));
            //base64编码的私钥
            byte[] decoded = Base64.decodeBase64(privateKey);
            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(ENCRYPTION_RSA).generatePrivate(new PKCS8EncodedKeySpec(decoded));
            //RSA解密
            Cipher cipher = Cipher.getInstance(ENCRYPTION_RSA);
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            return new String(cipher.doFinal(inputByte));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static RSAKeyPair getRsaKeyPair() throws NoSuchAlgorithmException {
        // KeyPairGenerator类用于生成公钥和私钥对，基于RSA算法生成对象
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ENCRYPTION_RSA);
        // 初始化密钥对生成器，密钥大小为96-1024位
        keyPairGen.initialize(RSA_KEY_SIZE);
        // 生成一个密钥对，保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥
        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
        // 得到私钥字符串
        String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
        System.out.println(publicKeyString);
        System.out.println(privateKeyString);
        return RSAKeyPair.of(publicKeyString, privateKeyString);
    }

    public static class RSAKeyPair {
        private String publicKey;
        private String privateKey;

        public static RSAKeyPair of(String publicKey, String privateKey) {
            RSAKeyPair rsaKeyPair = new RSAKeyPair();
            rsaKeyPair.publicKey = publicKey;
            rsaKeyPair.privateKey = privateKey;
            return rsaKeyPair;
        }

        public String getPublicKey() {
            return publicKey;
        }

        public String getPrivateKey() {
            return privateKey;
        }
    }

    public static void main(String[] args) throws NoSuchAlgorithmException {
//        String content = "苹果是这种模式的始作俑者，也通过商业模式的变革给信息产业的发展充足了动力，但是，这种模式本身也存在很多问题，直接的后果就是不同的开发者和不同类型的应用条块分隔，手机上经常需要安装同类的不同类的大大小小的应用，增加了硬件的负担，给消费者的使用体验也造成了影响。" +
//                "\r\n因此，Facebook和微软都不断的暗示，应用的未来前景正变得暗淡，模拟人类互动的聊天机器人、软件编程才是新兴趋势。除了竞争对手之间的战略战术之外，也有希望借助弯道超车的机会颠覆苹果模式的想法和做法。";
        String content = "123123";
//        String encryptContent = aesEncryptToHex(content, "cygw");
//        String decryptContent = aesDecryptFromHex(encryptContent, "cygw");
//        System.out.println("加密前:" + content);
//        System.out.println("加密后:" + encryptContent);
//        System.out.println("解密后:" + decryptContent);
//        System.out.println("加密/解密前后是否相同:" + content.equals(decryptContent));
//        System.out.println("MD5加密后:" + md5HexDigest(content));
//        System.out.println("SHA1加密后:" + sha1HexDigest(content));
//        System.out.println(System.currentTimeMillis()/1000);
        RSAKeyPair rsaKeyPair = getRsaKeyPair();
        String publicKey = rsaKeyPair.getPublicKey();
        String privateKey = rsaKeyPair.getPrivateKey();
        String encryptContent = rsaEncryptToHex(content, publicKey);
        System.out.println(encryptContent);
        String decryptContent = rsaDecryptFromHex(encryptContent, privateKey);
        System.out.println(decryptContent);
    }
}
